package com.example.pictureview.widget;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2017/9/20 0020.
 */

public class NineGridLayout extends ViewGroup {

    private static final int INVALID_POSITION = -1;

    private static final float DEFUALT_SPACING = 3f;
    private static final int MAX_COUNT = 9;

    protected Context mContext;
    private int mSpacing = (int) DEFUALT_SPACING;
    private final int mColumns = 3;
    private int mRows;
    private int mTotalWidth;
    private int mSingleWidth;

    private List<String> mUrlList = new ArrayList<>();
    private Rect mTouchFrame;
    private int mChindCount;
    private ImageLoader mImageLoader;
    private RecycleBin mRecycleBin = new RecycleBin();
    private boolean mDataChanged;
    private int mDownTouchPosition;
    private View mDownTouchView;
    private GestureDetector mGestureDetector;

    public OnItemClickListener getOnItemClickListener() {
        return mOnItemClickListener;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.mOnItemClickListener = onItemClickListener;
    }

    private OnItemClickListener mOnItemClickListener;

    public NineGridLayout(Context context) {
        super(context);
        init(context);
    }

    public NineGridLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        setVisibility(VISIBLE);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mGestureDetector == null) {
            mGestureDetector = new GestureDetector(getContext(), onGestureListener);
            mGestureDetector.setIsLongpressEnabled(true);
        }
    }

    private GestureDetector.SimpleOnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onDown(MotionEvent e) {
            mDownTouchPosition = pointToPosition((int) e.getX(), (int) e.getY());

            if (mDownTouchPosition >= 0) {
                mDownTouchView = getChildAt(mDownTouchPosition);
                mDownTouchView.setPressed(true);
                return true;
            }
            return false;

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            if (mDownTouchPosition >= 0) {
                performItemClick(mDownTouchView, mDownTouchPosition);
                return true;
            }

            return false;
        }
    };

    public boolean performItemClick(View view, int position) {
        final boolean result;
        if (mOnItemClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            mOnItemClickListener.onItemClick(this, view, position, mUrlList);
            result = true;
        } else {
            result = false;
        }

        if (view != null) {
            view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        }
        return result;
    }

    public interface OnItemClickListener {
        public void onItemClick(ViewGroup group, View view, int position, List<String> urls);
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mImageLoader = null;
        mRecycleBin.clear();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.i("@@", "@@onMeasure" + mChindCount);

        int measureWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        mTotalWidth = measureWidth;
        mSingleWidth = mChindCount == 0 ? 0 : mChindCount == 1 ? mTotalWidth / 2 : (mTotalWidth - mSpacing * (3 - 1)) / 3;
        mRows = mChindCount % 3 == 0 ? mChindCount / 3 : mChindCount / 3 + 1;
        int specModeHeight = MeasureSpec.getMode(heightMeasureSpec);
        int specSizeHeight = MeasureSpec.getSize(heightMeasureSpec);

        final int singleHeight = mSingleWidth;


        switch (specModeHeight) {
            case MeasureSpec.AT_MOST:
                if (mRows == 0) {
                    specSizeHeight = mRows * singleHeight;
                } else {
                    specSizeHeight = (mRows - 1) * mSpacing + mRows * singleHeight;
                }
//                measureHeight = specSize;
                break;
            case MeasureSpec.EXACTLY:

                break;
            case MeasureSpec.UNSPECIFIED:
                if (mRows == 0) {
                    specSizeHeight = mRows * singleHeight;
                } else {
                    specSizeHeight = (mRows - 1) * mSpacing + mRows * singleHeight;
                }
                break;
        }


        setMeasuredDimension(measureWidth,
                specSizeHeight);
    }


    private boolean mBlockLayoutRequests;

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        Log.i("@@", "@@onLayout" + mChindCount);
        final boolean blockLayoutRequests = mBlockLayoutRequests;
        if (blockLayoutRequests) {
            return;
        }
        mBlockLayoutRequests = true;


        mRecycleBin.recycleAllViews();
        detachAllViewsFromParent();

        layoutImageView();
        invalidate();
        mRecycleBin.detachView();
        mDataChanged = false;

        if (!blockLayoutRequests) {
            mBlockLayoutRequests = false;
        }
    }

    @Override
    public void requestLayout() {
        if (!mBlockLayoutRequests) {
            super.requestLayout();
            Log.i("@@", "@@requestLayout" + mChindCount);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean retValue = mGestureDetector.onTouchEvent(event);
        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP) {
            onUp();
        } else if (action == MotionEvent.ACTION_CANCEL) {
            onCancel();
        }
        return retValue;
    }

    void onCancel() {
        onUp();
    }

    void onUp() {
        dispatchUnpress();
    }

    private void dispatchUnpress() {
        for (int i = getChildCount() - 1; i >= 0; i--) {
            getChildAt(i).setPressed(false);
        }
        setPressed(false);
    }

    public int pointToPosition(int x, int y) {
        Rect frame = mTouchFrame;
        if (frame == null) {
            mTouchFrame = new Rect();
            frame = mTouchFrame;
        }

        final int count = getChildCount();
        for (int i = 0; i < count; ++i) {
            View child = getChildAt(i);
            child.getHitRect(frame);
            if (frame.contains(x, y)) {
                return i;
            }
        }
        return INVALID_POSITION;
    }

    public void setSpacing(int spacing) {
        mSpacing = spacing;
        requestLayout();
    }


    public void setUrlList(List<String> urlList, ImageLoader imageLoader) {
        mDataChanged = true;
        mUrlList = urlList;
        mChindCount = getListSize(mUrlList);
        mImageLoader = imageLoader;
        requestLayout();
    }


    private void layoutImageView() {
        final int singleWidth = mSingleWidth;
        int singleHeight = singleWidth;
        int index = 0;

        int topEdge = 0;
        for (int i = 0; i < mRows; ++i) {
            int leftEdge = 0;
            for (int j = 0; j < mColumns; ++j) {
                if (index < mChindCount) {

                    final String url = mUrlList.get(index);
                    ImageView image = createImageView(index, url, leftEdge, topEdge);
                    ++index;
                }
                leftEdge += (singleWidth + mSpacing);
            }
            topEdge += (singleHeight + mSpacing);
        }
    }


    private ImageView createImageView(final int i, final String url, int leftEdge, int topEdge) {
        ImageView imageView = null;
        imageView = (ImageView) mRecycleBin.get(i);
        if (imageView == null) {
            imageView = new ImageView(mContext);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        }
        setUpChild(imageView, url, i, leftEdge, topEdge);
//        if (!mDataChanged) {
//            imageView = (ImageView) mRecycleBin.get(i);
//            if (imageView == null) {
//                imageView = new ImageView(mContext);
//                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
//            }
//            setUpChild(imageView, url, i,leftEdge,topEdge);
//            return imageView;
//        }
//
//        imageView = new ImageView(mContext);
//        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
//        setUpChild(imageView, url, i,leftEdge,topEdge);
        return imageView;
    }

    private void setUpChild(ImageView view, String url, int i, int leftEdge, int topEdge) {
        if (mImageLoader != null) {
            mImageLoader.loadImage(view, url);
        }
        LayoutParams params = view.getLayoutParams();
        if (params == null) {
            params = generateDefaultLayoutParams();
        }
        addViewInLayout(view, i, params, true);
        view.measure(MeasureSpec.makeMeasureSpec(mSingleWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mSingleWidth, MeasureSpec.EXACTLY));
        view.layout(leftEdge, topEdge, leftEdge + view.getMeasuredWidth(), topEdge + view.getMeasuredHeight());


    }

    int getListSize(List<String> list) {
        if (list == null) {
            return 0;
        }
        return list.size();
    }


    class RecycleBin {
        private final SparseArray<View> mScrapHeap = new SparseArray<View>();

        public void put(int position, View v) {
            mScrapHeap.put(position, v);
        }

        View get(int position) {
            View result = mScrapHeap.get(position);
            if (result != null) {
                mScrapHeap.delete(position);
            }
            return result;
        }

        void detachView() {
            final SparseArray<View> scrapHeap = mScrapHeap;
            final int count = scrapHeap.size();
            for (int i = 0; i < count; i++) {
                final View view = scrapHeap.valueAt(i);
                if (view != null) {
                    removeDetachedView(view, true);
                    if (mImageLoader != null) {
                        mImageLoader.cancleImageViewWork((ImageView) view);
                    }
                }
            }
        }

        void clear() {
            detachView();
            mScrapHeap.clear();
        }

        void recycleAllViews() {
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                View v = getChildAt(i);
                put(i, v);
            }
        }
    }

}